﻿using System;
using EPiServer;
using EPiServer.Core;
using log4net;
using PageTypeBuilder;

namespace TemplateFoundation.Core
{
    /// <summary>
    /// Used to manage caching for the PageFactory class
    /// </summary>
    /// <remarks>Note that the PageFactory cache won't be automatically updated when a page is deleted using the DataFactory.Delete method</remarks>
    public class PageFactoryCache
    {
        private static readonly ILog _logger = LogManager.GetLogger(typeof (PageFactoryCache));

        static PageFactoryCache()
        {
            //Ensure caches for pages by page type are cleared appropriately
            DataFactory.Instance.PublishedPage+=UpdateCacheForGetPagesByPageTypeOnPublish;
            DataFactory.Instance.MovedPage+=UpdateCacheForGetPagesByPageTypeOnMove;

            _logger.Debug("PageFactoryCache instantiated");
        }

        /// <summary>
        /// Updates the cache for the page type being published
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        static void UpdateCacheForGetPagesByPageTypeOnPublish(object sender, PageEventArgs e)
        {
            if (e.Page==null)
                return;

            var pageType = PageTypeResolver.Instance.GetPageTypeType(e.Page.PageTypeID);

            if (pageType!=null)
            {
                _logger.DebugFormat("Refreshing cache for page type {0}", e.Page.PageTypeName);

                RefreshCacheForPageType(pageType);
            }
        }

        /// <summary>
        /// Updates the cache for the page type of the page that was moved
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        static void UpdateCacheForGetPagesByPageTypeOnMove(object sender, PageEventArgs e)
        {
            var page = e.PageLink.GetPage();

            RefreshCacheForPageType(PageTypeResolver.Instance.GetPageTypeType(page.PageTypeID));
        }

        /// <summary>
        /// Refreshes the PageFactory cache for the specified page type
        /// </summary>
        /// <param name="pageType"></param>
        public static void RefreshCacheForPageType(Type pageType)
        {
            if (pageType==null)
                throw new ArgumentNullException("pageType", "No page type specified");

            _logger.DebugFormat("Refreshing cache for page type {0}", pageType.Name);

            // Clear visitor-filtered cache for the page type (if indeed a filtered cache exists for the page type)
            if (CacheManager.RuntimeCacheGet(GetPagesByTypeCacheKey(pageType, true)) as PageDataCollection != null)
            {
                CacheManager.RuntimeCacheRemove(GetPagesByTypeCacheKey(pageType, true));
                PageFactory.Instance.GetPagesByType(pageType, true);
            }

            // Trigger non-filtered cache update for the page type (if indeed a non-filtered cache exists for the page type)
            if (CacheManager.RuntimeCacheGet(GetPagesByTypeCacheKey(pageType, false)) as PageDataCollection != null)
            {
                CacheManager.RuntimeCacheRemove(GetPagesByTypeCacheKey(pageType, false));
                PageFactory.Instance.GetPagesByType(pageType, false);
            }
        }

        /// <summary>
        /// Generates a cache key used for the PageFactory cache
        /// </summary>
        /// <param name="pageType"></param>
        /// <param name="filterForVisitors"></param>
        /// <returns></returns>
        public static string GetPagesByTypeCacheKey(Type pageType, bool filterForVisitors)
        {
            return string.Concat(pageType.FullName, filterForVisitors);
        }
    }
}
